//package com.geek.factory.service.impl;
//
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//import com.geek.factory.entity.Menu;
//import com.geek.factory.mapper.MetaMapper;
//import com.geek.factory.service.MenuService;
//import com.geek.factory.mapper.MenuMapper;
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.geek.factory.service.MetaService;
//import com.geek.factory.vo.MenuVO;
//import org.springframework.beans.BeanUtils;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.util.ArrayList;
//import java.util.List;
//
///**
// * <p>
// *  服务实现类
// * </p>
// *
// * @author author
// * @since 2025-06-23
// */
////@CacheConfig(cacheNames = "menu" , keyGenerator = "keyGenerator")
//@Service
//public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
//    @Autowired
//    private MenuMapper menuMapper;
//
//    //根据当前登录者的ID，查询其拥有的菜单
////    @Cacheable
//    @Transactional(readOnly = true)
//    @Override
//    public List<MenuVO> findAll(Long userId) {
//        List<MenuVO> list = new ArrayList<>();
//
//        //查询一级菜单
//        List<Menu> firstMenus = menuMapper.selectFirstByUid(userId);
//        firstMenus.forEach(menu ->{
//            //组装一级菜单
//            MenuVO first = new MenuVO();
//            BeanUtils.copyProperties(menu , first);
//
//            //查询二级菜单
//            Integer id = menu.getId();
//            List<MenuVO> children = menuMapper.selectSecondById(id);
//            //组装二级菜单
//            first.setChildren(children);
//            list.add(first);
//        });
//        return list;
//    }
//
//    @Autowired
//    private MetaMapper metaMapper;
//
//    @Override
//    public List<Menu> getAllMenus() {
//        List<Menu> menus = this.list();
//        for (Menu menu : menus) {
//            menu.setMeta(metaMapper.selectById(menu.getMetaId()));
//        }
//        return menus;
//    }
//
//
//    @Override
//    public Menu getMenuById(Integer id) {
//        Menu menu = this.getById(id);
//        if (menu != null) {
//            menu.setMeta(metaMapper.selectById(menu.getMetaId()));
//        }
//        return menu;
//    }
//
//    @Override
//    @Transactional
//    public boolean addMenu(Menu menu) {
//        // 1. 先插入 meta 表
//        if (menu.getMeta() != null) {
//            metaMapper.insert(menu.getMeta());
//            // 2. 获取自增主键
//            menu.setMetaId(menu.getMeta().getId());
//        }
//        // 3. 再插入 menu 表
//        return this.save(menu);
//    }
//
//@Override
//public boolean updateMenu(Menu menu) {
//    // 1. 先更新 menu 表
//    boolean menuUpdated = this.updateById(menu);
//
//    // 2. 再更新 meta 表
//    if (menu.getMeta() != null && menu.getMeta().getId() != null) {
//        metaMapper.updateById(menu.getMeta());
//    }
//
//    return menuUpdated;
//}
//
//    @Override
//    public boolean deleteMenu(Integer id) {
//        return this.removeById(id);
//    }
//
//    @Autowired
//    private MetaService metaService;
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean deleteMenuCascade(Integer id) {
//        // 1. 先查询菜单信息，获取metaId
//        Menu menu = this.getById(id);
//        if (menu == null) {
//            return false;
//        }
//
//        // 2. 删除菜单
//        boolean menuDeleted = this.removeById(id);
//        if (!menuDeleted) {
//            return false;
//        }
//
//        // 3. 如果存在关联的meta数据，则删除meta数据
//        if (menu.getMetaId() != null) {
//            metaService.removeById(menu.getMetaId());
//        }
//
//        return true;
//    }
//}
package com.geek.factory.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.geek.factory.constant.RedisConstant;
import com.geek.factory.entity.Menu;
import com.geek.factory.mapper.MetaMapper;
import com.geek.factory.service.MenuService;
import com.geek.factory.mapper.MenuMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geek.factory.service.MetaService;
import com.geek.factory.vo.MenuVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author author
 * @since 2025-06-23
 */
@Slf4j
@CacheConfig(cacheNames = RedisConstant.MENU_KEY)
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    //根据当前登录者的ID，查询其拥有的菜单
    @Cacheable(key = "'user_' + #userId")
    @Transactional(readOnly = true)
    @Override
    public List<MenuVO> findAll(Long userId) {
        List<MenuVO> list = new ArrayList<>();

        //查询一级菜单
        List<Menu> firstMenus = menuMapper.selectFirstByUid(userId);
        firstMenus.forEach(menu ->{
            //组装一级菜单
            MenuVO first = new MenuVO();
            BeanUtils.copyProperties(menu , first);

            //查询二级菜单
            Integer id = menu.getId();
            List<MenuVO> children = menuMapper.selectSecondById(id);
            //组装二级菜单
            first.setChildren(children);
            list.add(first);
        });
        return list;
    }

    @Autowired
    private MetaMapper metaMapper;

    @Cacheable(key = "'" + RedisConstant.ALL_MENUS_KEY + "'")
    @Override
    public List<Menu> getAllMenus() {
        List<Menu> menus = this.list();
        for (Menu menu : menus) {
            menu.setMeta(metaMapper.selectById(menu.getMetaId()));
        }
        return menus;
    }


    @Cacheable(key = "'" + RedisConstant.MENU_ID_KEY + "' + #id")
    @Override
    public Menu getMenuById(Integer id) {
        Menu menu = this.getById(id);
        if (menu != null) {
            menu.setMeta(metaMapper.selectById(menu.getMetaId()));
        }
        return menu;
    }

    @CacheEvict(allEntries = true)
    @Override
    @Transactional
    public boolean addMenu(Menu menu) {
        // 1. 先删除缓存
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);

        // 2. 先插入 meta 表
        if (menu.getMeta() != null) {
            metaMapper.insert(menu.getMeta());
            // 3. 获取自增主键
            menu.setMetaId(menu.getMeta().getId());
        }

        // 4. 再插入 menu 表
        boolean result = this.save(menu);

        // 5. 延迟双删策略，再次删除缓存
        try {
            TimeUnit.MILLISECONDS.sleep(300);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
        } catch (InterruptedException e) {
            log.error("延迟双删失败", e);
            Thread.currentThread().interrupt();
        }

        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean updateMenu(Menu menu) {
        // 1. 先删除缓存
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.MENU_ID_KEY + menu.getId());

        // 2. 先更新 menu 表
        boolean menuUpdated = this.updateById(menu);

        // 3. 再更新 meta 表
        if (menu.getMeta() != null && menu.getMeta().getId() != null) {
            metaMapper.updateById(menu.getMeta());
        }

        // 4. 延迟双删策略，再次删除缓存
        try {
            TimeUnit.MILLISECONDS.sleep(300);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.MENU_ID_KEY + menu.getId());
        } catch (InterruptedException e) {
            log.error("延迟双删失败", e);
            Thread.currentThread().interrupt();
        }

        return menuUpdated;
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean deleteMenu(Integer id) {
        // 1. 先删除缓存
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.MENU_ID_KEY + id);

        // 2. 删除数据
        boolean result = this.removeById(id);

        // 3. 延迟双删策略，再次删除缓存
        try {
            TimeUnit.MILLISECONDS.sleep(300);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.MENU_ID_KEY + id);
        } catch (InterruptedException e) {
            log.error("延迟双删失败", e);
            Thread.currentThread().interrupt();
        }

        return result;
    }

    @Autowired
    private MetaService metaService;

    @CacheEvict(allEntries = true)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMenuCascade(Integer id) {
        // 1. 先删除缓存
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
        redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.MENU_ID_KEY + id);

        // 2. 先查询菜单信息，获取metaId
        Menu menu = this.getById(id);
        if (menu == null) {
            return false;
        }

        // 3. 删除菜单
        boolean menuDeleted = this.removeById(id);
        if (!menuDeleted) {
            return false;
        }

        // 4. 如果存在关联的meta数据，则删除meta数据
        if (menu.getMetaId() != null) {
            metaService.removeById(menu.getMetaId());
        }

        // 5. 延迟双删策略，再次删除缓存
        try {
            TimeUnit.MILLISECONDS.sleep(300);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.ALL_MENUS_KEY);
            redisTemplate.delete(RedisConstant.MENU_KEY + "::" + RedisConstant.MENU_ID_KEY + id);
        } catch (InterruptedException e) {
            log.error("延迟双删失败", e);
            Thread.currentThread().interrupt();
        }

        return true;
    }
}
